Fix updating sources with more than one crate
authorAlex Crichton <alex@alexcrichton.com>
Mon, 13 Oct 2014 16:54:08 +0000 (09:54 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 13 Oct 2014 16:54:08 +0000 (09:54 -0700)
When a source has multiple crates inside of it, `cargo update -p foo` would
previously not actually update anything because the extra crates were continuing
to lock the source to the same revision. This change updates the "avoid me"
logic to avoid *sources*, not *packages*.

Closes #697

src/cargo/ops/cargo_generate_lockfile.rs
tests/test_cargo_compile_git_deps.rs

index 10095a69dbdd17c91613ac7e2f09fdf5bca97e30..533caed5c9d2f24ea3c96366df586e21476cc2c7 100644 (file)
@@ -66,9 +66,10 @@ pub fn update_lockfile(manifest_path: &Path,
             let mut to_avoid = HashSet::new();
             let dep = try!(resolve.query(name));
             if opts.aggressive {
-                fill_with_deps(&resolve, dep, &mut to_avoid);
+                let mut visited = HashSet::new();
+                fill_with_deps(&resolve, dep, &mut to_avoid, &mut visited);
             } else {
-                to_avoid.insert(dep);
+                to_avoid.insert(dep.get_source_id());
                 match opts.precise {
                     Some(precise) => {
                         sources.push(dep.get_source_id().clone()
@@ -78,8 +79,9 @@ pub fn update_lockfile(manifest_path: &Path,
                 }
             }
             sources.extend(resolve.iter()
-                                  .filter(|p| !to_avoid.contains(p))
-                                  .map(|p| p.get_source_id().clone()));
+                                  .map(|p| p.get_source_id())
+                                  .filter(|s| !to_avoid.contains(s))
+                                  .map(|s| s.clone()));
         }
         None => sources.extend(package.get_source_ids().into_iter()),
     }
@@ -93,12 +95,14 @@ pub fn update_lockfile(manifest_path: &Path,
     return Ok(());
 
     fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,
-                          set: &mut HashSet<&'a PackageId>) {
-        if !set.insert(dep) { return }
+                          set: &mut HashSet<&'a SourceId>,
+                          visited: &mut HashSet<&'a PackageId>) {
+        if !visited.insert(dep) { return }
+        set.insert(dep.get_source_id());
         match resolve.deps(dep) {
             Some(mut deps) => {
                 for dep in deps {
-                    fill_with_deps(resolve, dep, set);
+                    fill_with_deps(resolve, dep, set, visited);
                 }
             }
             None => {}
index 05d41377425a7515e03f24ac2edfe07204b50d15..8b4da434cd23f65e236e8db2533f5b6492dde60c 100644 (file)
@@ -1387,3 +1387,43 @@ following:
   foo:0.[..].0
 "));
 })
+
+test!(update_one_dep_in_repo_with_many_deps {
+    let foo = git_repo("foo", |project| {
+        project.file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.5.0"
+            authors = ["wycats@example.com"]
+        "#)
+        .file("src/lib.rs", "")
+        .file("a/Cargo.toml", r#"
+            [package]
+            name = "a"
+            version = "0.5.0"
+            authors = ["wycats@example.com"]
+        "#)
+        .file("a/src/lib.rs", "")
+    }).assert();
+
+    let p = project("project")
+        .file("Cargo.toml", format!(r#"
+            [project]
+            name = "project"
+            version = "0.5.0"
+            authors = []
+            [dependencies.foo]
+            git = '{}'
+            [dependencies.a]
+            git = '{}'
+        "#, foo.url(), foo.url()).as_slice())
+        .file("src/main.rs", "fn main() {}");
+
+    assert_that(p.cargo_process("generate-lockfile"), execs().with_status(0));
+    assert_that(p.process(cargo_dir().join("cargo")).arg("update")
+                 .arg("-p").arg("foo"),
+                execs().with_status(0)
+                       .with_stdout(format!("\
+Updating git repository `{}`
+", foo.url())));
+})